package me.zhengjie.modules.web.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.thread.ThreadUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import me.zhengjie.config.exception.WeChatException;
import me.zhengjie.constant.ConstantUtils;
import me.zhengjie.modules.system.domain.*;
import me.zhengjie.modules.system.service.*;
import me.zhengjie.modules.system.service.dto.*;
import me.zhengjie.modules.web.domain.ExamResultResponse;
import me.zhengjie.modules.web.domain.ModifyMobileRequest;
import me.zhengjie.modules.web.domain.PersonalCenterResponse;
import me.zhengjie.modules.web.domain.classes.ClassesInfoResp;
import me.zhengjie.modules.web.domain.course.CourseInfoResp;
import me.zhengjie.modules.web.domain.course.CourseOrderResp;
import me.zhengjie.modules.web.domain.identity.IdentityListResp;
import me.zhengjie.modules.web.enums.VerifyCodeSceneEnum;
import me.zhengjie.modules.web.service.IPersonalCenterService;
import me.zhengjie.modules.web.service.mybatisplus.ICourseApplicantsPlusService;
import me.zhengjie.modules.web.service.mybatisplus.ICourseClassStudentPlusService;
import me.zhengjie.modules.web.service.mybatisplus.ICourseOrderPlusService;
import me.zhengjie.modules.web.service.mybatisplus.IExamResultPlusService;
import me.zhengjie.utils.DateUtil;
import me.zhengjie.utils.RedisUtils;
import me.zhengjie.utils.StringUtils;
import me.zhengjie.utils.enums.OrderTypeEnum;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.CompletableFuture;

@Service
public class PersonalCenterServiceImpl implements IPersonalCenterService {

    @Autowired
    RichTextService richTextService;

    @Autowired
    private WxUserService wxUserService;

    @Autowired
    private RedisUtils redisUtils;

    @Autowired
    private AtmrService atmrService;

    @Autowired
    private IdentityItemService identityItemService;

    @Autowired
    private CourseClassService courseClassService;

    @Autowired
    private CourseInfoService courseInfoService;

    @Autowired
    private CourseClockService courseClockService;

    @Autowired
    private IExamResultPlusService examResultPlusService;

    @Autowired
    private ICourseOrderPlusService courseOrderPlusService;

    @Autowired
    private ICourseClassStudentPlusService courseClassStudentPlusService;

    @Autowired
    private ICourseApplicantsPlusService applicantsPlusService;

    /**個人中心
     * @param openId
     * @return
     */
    @Override
    public PersonalCenterResponse userCenter(String openId) {
        PersonalCenterResponse response = new PersonalCenterResponse();

        WxUser wxUser = wxUserService.findByOpenId(openId);

        copyUserProperties(response, wxUser);

        response.setIdentityList(queryIdentityList());

        Map<String, CourseInfo> courseMap = new HashMap<>();
        Map<String, List<CourseApplicants>> applicantsListMap = new HashMap<>();
        Map<String, Integer> applicantsNumberMap = new HashMap<>();

        CompletableFuture<List<ExamResultResponse>> queryExamResultFuture = CompletableFuture.supplyAsync(() -> queryExamResultList(openId));

        CompletableFuture<List<CourseOrderResp>> queryCourseOrderFuture = CompletableFuture.supplyAsync(() -> queryCourseOrderList(openId, courseMap, applicantsListMap, applicantsNumberMap));

        CompletableFuture<List<CourseInfoResp>> queryCourseFuture = CompletableFuture.supplyAsync(() -> queryCourseList(openId, courseMap, applicantsListMap, applicantsNumberMap));

        CompletableFuture<List<ClassesInfoResp>> queryClassFuture = CompletableFuture.supplyAsync(() -> queryClassList(openId, courseMap, applicantsListMap, applicantsNumberMap));

        CompletableFuture.allOf(queryExamResultFuture, queryCourseOrderFuture, queryCourseFuture, queryClassFuture).join();

        List<ExamResultResponse> reportList = null;
        List<CourseOrderResp> courseOrderRespList = null;
        List<CourseInfoResp> courseList = null;
        List<ClassesInfoResp> classList = null;
        try {
            reportList = queryExamResultFuture.get();
            courseOrderRespList = queryCourseOrderFuture.get();
            courseList = queryCourseFuture.get();
            classList = queryClassFuture.get();
        } catch (Exception e) {
            e.printStackTrace();
        }
        response.setOrderList(courseOrderRespList);
        response.setClassList(classList);
        response.setCourseList(courseList);
        response.setReportList(reportList);
        return response;
    }

    @Override
    public boolean modifyMobile(ModifyMobileRequest request) {
        WxUser user = wxUserService.findByOpenId(request.getOpenId());
        if (Objects.isNull(user)) {
            user = new WxUser();
            user.setMobile(request.getMobile());
            user.setSex(request.getSex());
            user.setOpenId(request.getOpenId());
            user.setCity(request.getCity());
            user.setCompany(request.getCompany());
            user.setProvince(request.getProvince());
            user.setAddress(request.getAddress());
            user.setRealName(request.getRealName());
            user.setBirthday(request.getBirthday());
            user.setHeadimgurl(request.getHeadPic());
            boolean result = Objects.nonNull(wxUserService.create(user));
            if (result) {
                modifyClassStudent(request.getOpenId(), request.getMobile(), request.getRealName());
            }
            return result;
        }
        String mobile = request.getMobile();
        String code = request.getCode();
        Object value = redisUtils.get(VerifyCodeSceneEnum.getRedisKey(mobile, VerifyCodeSceneEnum.ModifyMobile));
        if (Objects.isNull(value) || !String.valueOf(value).equals(code)) {
            throw new WeChatException("验证码不正确");
        }
        if (StringUtils.isNotBlank(request.getSex())) {
            user.setSex(request.getSex());
        }
        if (StringUtils.isNotBlank(request.getCompany())) {
            user.setCompany(request.getCompany());
        }
        if (StringUtils.isNotBlank(request.getCity())) {
            user.setCity(request.getCity());
        }
        if (StringUtils.isNotBlank(request.getProvince())) {
            user.setProvince(request.getProvince());
        }
        if (StringUtils.isNotBlank(request.getAddress())) {
            user.setAddress(request.getAddress());
        }
        if (StringUtils.isNotBlank(request.getBirthday())) {
            user.setBirthday(request.getBirthday());
        }
        if (StringUtils.isNotBlank(request.getHeadPic())) {
            user.setHeadimgurl(request.getHeadPic());
        }
        if (StringUtils.isNotBlank(request.getMobile())) {
            user.setMobile(mobile);
        }
        if (StringUtils.isNotBlank(request.getRealName())) {
            user.setRealName(request.getRealName());
        }
        wxUserService.update(user);
        modifyClassStudent(request.getOpenId(), request.getMobile(), request.getRealName());
        return true;
    }

    @Override
    public boolean createWxUser_other(ModifyMobileRequest request) {
        WxUser user = wxUserService.findByOpenId(request.getOpenId());
        if (null == user) {
            user = new WxUser();
            user.setMobile(request.getMobile());
            user.setSex(request.getSex());
            user.setOpenId(request.getOpenId());
            user.setCity(request.getCity());
            user.setCompany(request.getCompany());
            wxUserService.create(user);
            return true;
            //throw new WeChatException("用户信息不存在");
        } else {
            throw new WeChatException("用户信息已存在");
        }
    }

    private List<IdentityItemDto> getIdentityList(String identityNo) {
        IdentityItemQueryCriteria itemQueryCriteria = new IdentityItemQueryCriteria();
        if (StringUtils.isNotEmpty(identityNo)) {
            itemQueryCriteria.setItemNo(identityNo);
        }
        itemQueryCriteria.setStatus(1);
        itemQueryCriteria.setShowIndex(1);
        return identityItemService.queryAll(itemQueryCriteria);
    }

    private void modifyClassStudent(String openId, String mobile, String userName) {
        if (StringUtils.isBlank(openId)) {
            return;
        }
        ThreadUtil.execAsync(() -> {
            CourseClassStudent student = new CourseClassStudent();
            student.setUserName(userName);
            student.setPhoneNo(mobile);
            LambdaQueryWrapper<CourseClassStudent> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(CourseClassStudent::getOpenId, openId);
            boolean update = courseClassStudentPlusService.update(student, wrapper);
        });
    }


    private List<ExamResultResponse> queryExamResultList(String openId) {
        Page<ExamResult> page = Page.of(0, 5);
        LambdaQueryWrapper<ExamResult> examWrapper = new LambdaQueryWrapper<>();
        examWrapper.eq(ExamResult::getWxId, openId).orderByDesc(ExamResult::getExamTime);
        Page<ExamResult> examResultPage = examResultPlusService.page(page, examWrapper);

        List<ExamResult> list = examResultPage.getRecords();
        List<ExamResultResponse> reportList = new ArrayList<>();
        if (CollectionUtil.isEmpty(list)) {
            return reportList;
        }
        Map<String, AtmrDto> atmrMap = new HashMap<>();
        for (ExamResult examResultDto : list) {
            ExamResultResponse resultResponse = new ExamResultResponse();
            BeanUtil.copyProperties(examResultDto, resultResponse);
            AtmrDto atmrDto;
            if (Objects.isNull(atmrMap.get("atmrInfo" + examResultDto.getAtmrId()))) {
                atmrDto = atmrService.findById(Integer.parseInt(examResultDto.getAtmrId()));
                atmrMap.put("atmrInfo" + examResultDto.getAtmrId(), atmrDto);
            } else {
                atmrDto = atmrMap.get("atmrInfo" + examResultDto.getAtmrId());
            }
            if (Objects.nonNull(atmrDto)) {
                resultResponse.setAtmrName(atmrDto.getAtmrName());
                resultResponse.setAtmrType(atmrDto.getAtmrType());
                resultResponse.setAgeType(atmrDto.getAgeType());
            }
            reportList.add(resultResponse);
        }
        return reportList;
    }

    private void copyUserProperties(PersonalCenterResponse response, WxUser wxUser) {
        if (Objects.isNull(wxUser)) {
            return;
        }
        response.setMobile(wxUser.getMobile());
        response.setNickName(wxUser.getNickname());
        response.setHeadPic(wxUser.getHeadimgurl());
        response.setProfession(wxUser.getProfession());
        response.setCompany(wxUser.getCompany());
        response.setProvince(wxUser.getProvince());
        response.setCity(wxUser.getCity());
        response.setAddress(wxUser.getAddress());
        response.setRealName(wxUser.getRealName());
        response.setBirthday(wxUser.getBirthday());
        response.setSex(wxUser.getSex());
        String identityNo = wxUser.getIdentityNo();
        response.setIdentity(ConstantUtils.Simple_Member);
        if (StringUtils.isNotBlank(identityNo)) {
            List<IdentityItemDto> itemDtoList = getIdentityList(identityNo);
            if (CollectionUtil.isNotEmpty(itemDtoList)) {
                response.setIdentity(itemDtoList.get(0).getTitle());
            }
        }
    }

    private List<IdentityListResp> queryIdentityList() {
        List<IdentityItemDto> itemDtoList = getIdentityList("");
        List<IdentityListResp> identityRespList = new ArrayList<>();
        if (CollectionUtil.isEmpty(itemDtoList)) {
            return identityRespList;
        }

        itemDtoList.forEach(s -> {
            IdentityListResp resp = new IdentityListResp();
            BeanUtils.copyProperties(s, resp);
            identityRespList.add(resp);
        });
        return identityRespList;
    }

    private List<CourseOrderResp> queryCourseOrderList(String openId, Map<String, CourseInfo> courseMap, Map<String, List<CourseApplicants>> applicantsListMap, Map<String, Integer> applicantsNumberMap) {
        Page<CourseOrder> pageCourseOrder = Page.of(0, 3);
        LambdaQueryWrapper<CourseOrder> courseOrderWrapper = new LambdaQueryWrapper<>();
        courseOrderWrapper.eq(CourseOrder::getOpenId, openId);
        courseOrderWrapper.orderByDesc(CourseOrder::getOrderId);
        Page<CourseOrder> courseOrderPage = courseOrderPlusService.page(pageCourseOrder, courseOrderWrapper);
        List<CourseOrder> orderList = courseOrderPage.getRecords();

        List<CourseOrderResp> courseOrderRespList = new ArrayList<>();
        if (CollectionUtil.isEmpty(orderList)) {
            return courseOrderRespList;
        }
        orderList.forEach(s -> {
            CourseOrderResp orderResp = new CourseOrderResp();
            orderResp.setOrderStatus(s.getOrderStatus());
            orderResp.setOrderId(s.getOrderId());
            orderResp.setOrderSn(s.getOrderNo());
            orderResp.setOrderAmount(s.getOrderAmount());
            orderResp.setPayAmount(s.getPayAmount());
            orderResp.setPayStatus(s.getPayStatus());
            orderResp.setOrderStatus(s.getOrderStatus());
            orderResp.setOrderType(OrderTypeEnum.Course.getOrderType());
            CourseInfo courseInfo;
            String courseNo = s.getCourseNo();
            if (Objects.isNull(courseMap.get("courseInfo" + courseNo))) {
                courseInfo = courseInfoService.getInfoByNo(courseNo);
                courseMap.put("courseInfo" + courseNo, courseInfo);
            } else {
                courseInfo = courseMap.get("courseInfo" + courseNo);
            }
            if (Objects.nonNull(courseInfo)) {
                orderResp.setCourseCover(courseInfo.getCourseLogo());
                orderResp.setCourseName(courseInfo.getCourseName());
                orderResp.setClassName(courseInfo.getSubTitle());
            }
            if (s.getPayStatus().equals(ConstantUtils.Order_Payed)) {
                LambdaQueryWrapper<CourseApplicants> applicantsWrapper = new LambdaQueryWrapper<>();
                applicantsWrapper.eq(CourseApplicants::getOrderNo, s.getOrderNo());
                List<CourseApplicants> applicantsList = applicantsPlusService.list(applicantsWrapper);
                CourseInfoResp courseInfoResp = new CourseInfoResp();
                applicantsListMap.put(s.getOrderNo() + "_List", new ArrayList<>());
                applicantsNumberMap.put(s.getOrderNo() + "_Num", 1);
                if (CollectionUtil.isNotEmpty(applicantsList)) {
                    courseInfoResp.setApplicantsList(applicantsList);
                    applicantsListMap.put(s.getOrderNo() + "_List", applicantsList);
                    applicantsNumberMap.put(s.getOrderNo() + "_Num", applicantsList.size());
                }
            }
            courseOrderRespList.add(orderResp);
        });
        return courseOrderRespList;
    }

    private List<CourseInfoResp> queryCourseList(String openId, Map<String, CourseInfo> courseMap, Map<String, List<CourseApplicants>> applicantsListMap, Map<String, Integer> applicantsNumberMap) {
        Page<CourseOrder> pageCourseOrder = Page.of(0, 3);
        LambdaQueryWrapper<CourseOrder> courseOrderWrapperOne = new LambdaQueryWrapper<>();
        courseOrderWrapperOne.eq(CourseOrder::getOpenId, openId);
        courseOrderWrapperOne.eq(CourseOrder::getPayStatus, ConstantUtils.Order_Payed);
        courseOrderWrapperOne.orderByDesc(CourseOrder::getOrderId);
        Page<CourseOrder> courseOrderPageOne = courseOrderPlusService.page(pageCourseOrder, courseOrderWrapperOne);
        List<CourseOrder> payedList = courseOrderPageOne.getRecords();
        List<CourseInfoResp> courseList = new ArrayList<>();
        if (CollectionUtil.isEmpty(payedList)) {
            return courseList;
        }
        List<CourseInfoResp> finalCourseList = courseList;
        payedList.forEach(s -> {
            String courseNo = s.getCourseNo();
            //查询我的课程
            CourseInfo courseInfo;
            if (Objects.isNull(courseMap.get("courseInfo" + courseNo))) {
                courseInfo = courseInfoService.getInfoByNo(courseNo);
                if (Objects.nonNull(courseInfo)) {
                    courseMap.put("courseInfo" + courseNo, courseInfo);
                }
            } else {
                courseInfo = courseMap.get("courseInfo" + courseNo);
            }
            if (Objects.isNull(courseInfo)) {
                return;
            }
            CourseInfoResp courseInfoResp = new CourseInfoResp();
            Integer numbers = applicantsNumberMap.get(s.getOrderNo() + "_Num");
            List<CourseApplicants> applicantsList = applicantsListMap.get(s.getOrderNo() + "_List");
            if (Objects.isNull(numbers)) {
                LambdaQueryWrapper<CourseApplicants> applicantsWrapper = new LambdaQueryWrapper<>();
                applicantsWrapper.eq(CourseApplicants::getOrderNo, s.getOrderNo());
                List<CourseApplicants> applicantsList1 = applicantsPlusService.list(applicantsWrapper);
                if (CollectionUtil.isNotEmpty(applicantsList1)) {
                    numbers = applicantsList1.size();
                    applicantsList = applicantsList1;
                }
            }
            courseInfoResp.setCourseId(courseInfo.getCourseId());
            courseInfoResp.setCourseNo(courseInfo.getCourseNo());
            courseInfoResp.setCourseCover(courseInfo.getCourseLogo());
            courseInfoResp.setCourseName(courseInfo.getCourseName());
            courseInfoResp.setClassName(courseInfo.getSubTitle());
            courseInfoResp.setPrice(courseInfo.getSellPrice());
            courseInfoResp.setDiscountPrice(courseInfo.getDiscountPrice());
            courseInfoResp.setOpenTime(DateUtil.getTimeStamp(courseInfo.getOpenTime()));
            Date openDate = new Date(courseInfo.getOpenTime().getTime());
            courseInfoResp.setOpenStatus(openDate.compareTo(new Date()) > 0 ? 0 : 1);
            courseInfoResp.setNumbers(Objects.isNull(numbers) ? 1 : numbers);
            courseInfoResp.setApplicantsList(CollectionUtil.isNotEmpty(applicantsList) ? applicantsList : new ArrayList<>());
            finalCourseList.add(courseInfoResp);
        });
        return finalCourseList;
    }

    private List<ClassesInfoResp> queryClassList(String openId, Map<String, CourseInfo> courseMap, Map<String, List<CourseApplicants>> applicantsListMap, Map<String, Integer> applicantsNumberMap) {
        Page<CourseOrder> pageCourseOrder = Page.of(0, 3);
        LambdaQueryWrapper<CourseOrder> courseOrderWrapperOne = new LambdaQueryWrapper<>();
        courseOrderWrapperOne.eq(CourseOrder::getOpenId, openId);
        courseOrderWrapperOne.eq(CourseOrder::getPayStatus, ConstantUtils.Order_Payed);
        courseOrderWrapperOne.orderByDesc(CourseOrder::getOrderId);
        Page<CourseOrder> courseOrderPageOne = courseOrderPlusService.page(pageCourseOrder, courseOrderWrapperOne);
        List<CourseOrder> payedList = courseOrderPageOne.getRecords();
        List<ClassesInfoResp> classList = new ArrayList<>();
        if (CollectionUtil.isEmpty(payedList)) {
            return classList;
        }
        payedList.forEach(s -> {
            String courseNo = s.getCourseNo();
            //查询我的课程
            CourseInfo courseInfo;
            if (Objects.isNull(courseMap.get("courseInfo" + courseNo))) {
                courseInfo = courseInfoService.getInfoByNo(courseNo);
                if (Objects.nonNull(courseInfo)) {
                    courseMap.put("courseInfo" + courseNo, courseInfo);
                }
            } else {
                courseInfo = courseMap.get("courseInfo" + courseNo);
            }
            if (Objects.isNull(courseInfo)) {
                return;
            }
            //查询我的班级
            CourseClass courseClass = courseClassService.getClassByCourseNo(courseNo);
            ClassesInfoResp classInfo = new ClassesInfoResp();
            if (Objects.nonNull(courseClass)) {
                classInfo.setClassNo(courseClass.getClassNo());
                classInfo.setClassName(courseClass.getName());
            }
            classInfo.setSubTtitle(courseInfo.getSubTitle());
            classInfo.setCourseNo(courseNo);
            classInfo.setCourseName(courseInfo.getCourseName());
            classInfo.setCourseCover(courseInfo.getCourseLogo());

            CourseClockQueryCriteria courseClockQueryCriteria = new CourseClockQueryCriteria();
            courseClockQueryCriteria.setCourseNo(courseNo);
            courseClockQueryCriteria.setOpenId(openId);
            List<CourseClockDto> courseClockDtos = courseClockService.queryAll(courseClockQueryCriteria);
            int clockDays = 0;
            if (CollectionUtil.isNotEmpty(courseClockDtos)) {
                clockDays = courseClockDtos.size();
            }
            classInfo.setClockDays(clockDays);
            classList.add(classInfo);
        });
        return classList;
    }

}
